package multiplus.pack.spring.orm;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import multiplus.base.SqlMapRes;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.io.AbstractResource;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class AnnotationResource extends AbstractResource implements ApplicationContextAware, AnnotationResourceResolve {
	private Log log = LogFactory.getLog(AnnotationResource.class);
	private Resource _resource;
	private ApplicationContext applicationContext;

	public AnnotationResource() {
		System.out.println("asdfadsfdas");
	}

	public AnnotationResource(String path) {
		_resource = new ClassPathResource(path.replace("classpath:", ""));
	}

	public AnnotationResource(Resource resource) {
		this._resource = resource;
	}

	@Override
	public String getDescription() {
		return _resource.getDescription();
	}

	@Override
	public InputStream getInputStream() throws IOException {
		InputStream in = _resource.getInputStream();
		String[] maps = scanSqlmapConfig();
		return init(in, maps);
	}

	public InputStream init(InputStream in, String[] maps) {
		try {
			Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(in);
			Node sqlMapConfig = doc.getLastChild();
			NodeList sqlMaps = doc.getElementsByTagName("sqlMap");
			for (int i = 0; maps != null && i != maps.length; i++) {
				Element sqlMap = doc.createElement("sqlMap");
				sqlMap.setAttribute("resource", maps[i]);
				sqlMapConfig.appendChild(sqlMap);
			}

			// XML转字符串
			Transformer xformer = TransformerFactory.newInstance().newTransformer();
			xformer.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC, doc.getDoctype().getPublicId());
			xformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, doc.getDoctype().getSystemId());
			xformer.setOutputProperty("encoding", doc.getXmlEncoding());

			ByteArrayOutputStream bos = new ByteArrayOutputStream();
			xformer.transform(new DOMSource(doc), new StreamResult(bos));
			String xmlStr = bos.toString();
			System.out.println(xmlStr);
			return new ByteArrayInputStream(xmlStr.getBytes());
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	public String[] scanSqlmapConfig() {
		List<String> sqlMapFiles = new ArrayList<String>();
		// 根据class解析sqlmapconfig
		Map<String, AnnotationResourceResolve> resolve = this.applicationContext.getBeansOfType(AnnotationResourceResolve.class);
		AnnotationResourceResolve[] resolves = resolve.values().toArray(new AnnotationResourceResolve[]
			{});
		Map<String, Object> result = this.applicationContext.getBeansWithAnnotation(SqlMapRes.class);
		Iterator<Object> resultIterator = result.values().iterator();
		while (resultIterator.hasNext()) {
			Object entry = resultIterator.next();
			SqlMapRes res = entry.getClass().getAnnotation(SqlMapRes.class);
			if (entry != null) {
				for (int i = 0; resolves != null && i != resolves.length; i++) {
					resolves[i].resolve(res.value(), sqlMapFiles);
				}
			}
		}
		for (int i = 0; i != sqlMapFiles.size(); i++) {
			String res = sqlMapFiles.get(i);
			URL resUrl = Thread.currentThread().getContextClassLoader().getResource(res);
			if (resUrl != null) {
				log.debug(resUrl);
				continue;
			}
			sqlMapFiles.remove(i--);
		}
		return sqlMapFiles.toArray(new String[]
			{});
	}

	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		this.applicationContext = applicationContext;
	}

	@Override
	public void resolve(Class clszz, List<String> sqlMapFiles) {
		String name = clszz.getName();
		name = name.replace(".", "/");
		sqlMapFiles.add(name + "_SqlMap.xml");
		sqlMapFiles.add(name + "_SqlMap_ext.xml");
	}

}
